use std::{path::Path, fs};
use serde::{Serialize,Deserialize};
use toml;
use crate::{defines::*, log};

const PORT_MIN:u16 = 8082;

#[derive(Serialize,Deserialize,Clone)]
pub struct Protocol {
    pub(crate) check_client_heartbeat: bool,
    pub(crate) allow_client_any_heartbear: bool,
    pub(crate) send_heartbeat: bool,
}
impl Default for Protocol {
    fn default() -> Self {
        Self {
            check_client_heartbeat: true,
            allow_client_any_heartbear: true,
            send_heartbeat: false,
        }
    }
}

#[derive(Serialize,Deserialize,Clone)]
pub struct Engine {
    pub(crate) allow_background: bool,
    pub(crate) allow_bg_moves_gen: bool,
    pub(crate) use_moves_cache: bool,
    pub(crate) allow_whole_learn: bool,
    pub(crate) whole_bin_name: String,
}
impl Default for Engine {
    fn default() -> Self {
        Self {
            allow_background: true,
            allow_bg_moves_gen: false,
            use_moves_cache: false,
            allow_whole_learn: false,
            whole_bin_name: PATH_WHOLE_BIN.into(),
        }
    }
}

#[derive(Serialize,Deserialize,Clone)]
pub struct Config {
    pub(crate) port: u16,
    pub(crate) protocol: Protocol,
    pub(crate) engine: Engine,
}
impl Default for Config {
    fn default() -> Self {
        Self {
            port: PORT_MIN,
            protocol: Default::default(),
            engine: Default::default(),
        }
    }
}
impl Config {
    pub fn load<P: AsRef<Path>>(p:P) -> Self {
        let p = Path::new(p.as_ref());
        if let Ok(text) = fs::read_to_string(p) {
            if let Ok(loaded) = toml::from_str(text.as_str()) {
                if Self::check(&loaded) {
                    return loaded
                } else {
                    log::warning!("config '{}' content incorrent")
                }
            } else {
                log::warning!("config '{}' format damage", p.to_string_lossy())
            }
        } else {
            log::warning!("config '{}' not exist", p.to_string_lossy());
        }
        log::info!("config use default");
        let default = Self::default();
        if let Ok(text) = toml::to_string(&default) {
            fs::write(p, &text).unwrap();
        } else {
            log::warning!("config '{}' can't write", p.to_string_lossy());
        }
        default
    }
    fn check(a:&Config) -> bool {
        if a.port < PORT_MIN {return false}
        true
    }
}
